package org.pray.activity.prototype;

import java.util.ArrayList;
import java.util.List;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;

/**
 * ProToType 原型模式实现
 */

// 通过实现可克隆接口实现原型模式
@ToString
public class ProToType implements Cloneable {

    private String type;// 成员变量

    private List<String> buildLike;


    public String getType() {
        return type;
    }

    public List<String> getBuildLike() {
        return buildLike;
    }
    // 实现建造者模式：

    private ProToType(String type, List<String> buildLike) {
        this.type = type;
        this.buildLike = buildLike;
    }// 私有化构造方法

    public static ProToTypeBuilder builder() {
        return new ProToTypeBuilder();
    }

    public static class ProToTypeBuilder {

        private String type;// 成员变量

        private List<String> buildLike;

        public ProToTypeBuilder type(String type) {
            this.type = type;
            return this;
        }

        public ProToTypeBuilder buildLike(List<String> buildLike) {
            this.buildLike = buildLike;
            return this;
        }

        public ProToType build() {
            return new ProToType(type, buildLike);
        }
    }

    // 什么是原型模式：
    /**
     * 实际上与对象的拷贝息息相关，原型模式使用原型实例指定待创建对象的类型，
     * 并且通过复制这个原型来创建新的对象
     * 也就是说，原型对象作为模板，通过克隆操作，来产生更多的对象，就像细胞的复制一样
     *
     * @throws CloneNotSupportedException
     *
     */

    // 解释什么是浅拷贝和深拷贝？
    // 个人理解浅拷贝是对对象拷贝引用，而深拷贝是对对象及对象的属性进行复制拷贝

    // 补充：对基本类型的浅拷贝将会把之赋值给新对象，而一般对象是拷贝引用

    // **深拷贝：**无论是基本类型还是引用类型，深拷贝会将引用类型的所有内容，
    // 全部拷贝为一个新的对象，包括对象内部的所有成员变量，也会进行拷贝。

    // note:Java为我们提供的`clone`方法只会进行浅拷贝
    @Override
    public Object clone() throws CloneNotSupportedException {
        // 全部写齐全这样才做到了深拷贝
        ProToType proToType = (ProToType) super.clone();
        proToType.buildLike = new ArrayList<String>(buildLike);
        proToType.type = new String(type);
        // return super.clone();//super这个接口对成员变量是浅拷贝
        return proToType;
    }
}
